#ifndef BE0E1813_421A_4BCD_A33B_77432A3CA8D7
#define BE0E1813_421A_4BCD_A33B_77432A3CA8D7

#include<iostream>
#include"Socket.hpp"
#include"Log.hpp"
#include<sstream>
#include<pthread.h>
#include<vector>
#include<fstream>


//创建端口号。
static const int defaultport = 8080;
const string wwwroot =  "./wwwroot"; //定义web根目录为当前目录下的wwwroot 。
const string sep = "\r\n";
const string homepage = "index.html";

class HttpServer;

struct ThreadData
{
    ThreadData(int sock) 
        : sockfd(sock)
    {}
    int sockfd;
};


//有了这个请求类之后， 我们以后所有的请求都放到这里对象里面。
class Request
{
public:
    void Deserialize(string req)
    {
        string tmp;
        int pos = 0;

        //切割字符串
        while (true)
        {
            pos = req.find(sep);   //以/r/n为分隔符， 然后pos拿到第一个分隔符的位置
            if (pos == string::npos) break;     
            string temp = req.substr(0, pos);     //分割， 然后拿到整个传。 
            if (temp.empty()) break;

            req_header.push_back(temp);
            req.erase(0, pos + sep.size());
        }

        parse();
        //剩下的都是正文
        text = req;

        DebugPrint();
    }

    //对请求进行打印。
    void DebugPrint()
    {
        cout << "------------------------------------------------------------" << endl;
        for(auto& e : req_header)
        {
            cout << e << endl << endl; 
        }

        cout << method << endl << url << endl <<  http_version << endl << path << endl; 

        cout << text << endl;
    }

    //解析第一行
    void parse()
    {
        stringstream ss(req_header[0]);  //stringstream要包含头文件sstream 
        ss >> method >> url >> http_version;

        path = wwwroot;   //    ./wwwroot
        if (url == "/" || url == "/index.html") 
        {
            path += "/";  //   ./wwwroot/
            path += homepage;     //    ./wwwroot/a/b/c
        }
        else
        {
            path += "/";
            path += url;
        }
    }
public:
    vector<string> req_header;    //请求行
    string text;    //请求正文

    string method;
    string url;
    string http_version;

    string path;
};



class HttpServer
{
public:
    HttpServer(uint16_t port = defaultport) 
        :port_(port)  
    {}

    static string ReadWebContent(string str)
    {
        //注意， 这里读取文件可能读到的是不完整的！所以有坑， 但是本节内容不管。
        ifstream in(str);
        if (!in.is_open()) return "404";   //文件路径没有， 直接返回404

        string content;
        string line;
        while (getline(in, line))
        {
            content += line;
        }
        in.close();
        return content;
    }

    static void HandlerHttp(int sockfd)
    {
        char buffer[10240];
        ssize_t n = recv(sockfd, buffer, sizeof(buffer) - 1, 0);  //从某个地方读取， 然后读取的数据放到buffer里面。 从哪里读取， 
        if(n > 0)
        {
            buffer[n] = 0;

            //处理请求
            Request req;
            req.Deserialize(buffer);
            req.DebugPrint();

 
            
            //返回响应的过程。
            //先写正文内容
            string text = ReadWebContent(req.path);
            //然后写一下响应行
            string response_line = "HTTP/1.0 200 OK\r\n"; 

            //然后再写报头， 这里我们的报头只写正文的长度， 因为我们只讲了正文长度。 剩下的属性后面再讲。
            string response_header = "Content-Length: ";
            response_header += to_string(text.size());
            response_header += "\r\n";

            //空行
            string blank_line = "\r\n";

            //然后把所有的数据加到要发送到相应里面。
            string response;
            response += response_line;
            response += response_header;
            response += blank_line;
            response += text;
            //发送
            send(sockfd, response.c_str(), response.size(), 0);
        }

        close(sockfd);
    }

    static void* ThreadRun(void* args)
    {
        pthread_detach(pthread_self());
        ThreadData* td = static_cast<ThreadData*>(args);
        
        HandlerHttp(td->sockfd);
      
        delete td;
        return nullptr;
    }

    void start()
    {
        listensock_.InitSocket();
        listensock_.Bind(port_);
        listensock_.Listen();
        for (;;)
        {
            string clientip;
            uint16_t clientport;
            int sockfd = listensock_.Accept(&clientip, &clientport);
            pthread_t tid;
            ThreadData* td = new ThreadData(sockfd);
            td->sockfd = sockfd;
            pthread_create(&tid, nullptr, ThreadRun, td);
        }
    }



    ~HttpServer()
    {};
private:
    Socket listensock_;
    uint16_t port_;
};







#endif /* BE0E1813_421A_4BCD_A33B_77432A3CA8D7 */
